#include "TimerHandle.h"
#include "deplibUV.h"
#include <stdexcept>


inline static void onTimer(uv_timer_t* handle) {
    auto* timerHandle = static_cast<TimerHandle*>(handle->data);
    timerHandle->OnUvTimer();
}

inline static void onCloseTimer(uv_handle_t* handle) {
    delete reinterpret_cast<uv_timer_t*>(handle);
}

TimerHandle::TimerHandle(Listener* listener)
    : listener(listener), uv_handle(new uv_timer_t) {
    uv_handle->data = static_cast<void*>(this);

    const int err = uv_timer_init(DepLibUV::GetLoop(), uv_handle);
    if (err != 0) {
        delete uv_handle;
        uv_handle = nullptr;
        throw std::runtime_error("Failed to initialize uv_timer_t: " + std::string(uv_strerror(err)));
    }
}

TimerHandle::~TimerHandle() {
    if (!this->closed) {
        InternalClose();
    }
}

void TimerHandle::Start(uint64_t timeout, uint64_t repeat) {
    if (this->closed) {
        throw std::runtime_error("TimerHandle is closed");
    }

    this->timeout = timeout;
    this->repeat = repeat;


    if (uv_is_active(reinterpret_cast<uv_handle_t*>(this->uv_handle)) != 0) {
        // If the timer is already active, we need to stop it first.
        Stop();
    }

    const int err = uv_timer_start(uv_handle, static_cast<uv_timer_cb>(onTimer), timeout, repeat);
    if (err != 0) {
        throw std::runtime_error("Failed to start timer: " + std::string(uv_strerror(err)));
    }
}

void TimerHandle::Stop() {
    if (this->closed) {
        throw std::runtime_error("TimerHandle is closed");
    }

    const int err = uv_timer_stop(uv_handle);
    if (err != 0) {
        throw std::runtime_error("Failed to stop timer: " + std::string(uv_strerror(err)));
    }
}

void TimerHandle::Reset() {
    if (this->closed) {
        throw std::runtime_error("TimerHandle is closed");
    }

    if (uv_is_active(reinterpret_cast<uv_handle_t*>(this->uv_handle)) == 0) {
        return;
    }
    if (this->repeat == 0u) {
        return;
    }
    
    const int err = uv_timer_start(uv_handle, static_cast<uv_timer_cb>(onTimer), this->repeat, this->repeat);

    if (err != 0) {
        throw std::runtime_error("Failed to reset timer: " + std::string(uv_strerror(err)));
    }
}

void TimerHandle::Restart() {
    if (this->closed) {
        throw std::runtime_error("TimerHandle is closed");
    }

    if (uv_is_active(reinterpret_cast<uv_handle_t*>(this->uv_handle)) != 0) {
        Stop();
    }

    const int err = uv_timer_start(uv_handle, static_cast<uv_timer_cb>(onTimer), this->timeout, this->repeat);

    if (err != 0) {
        throw std::runtime_error("Failed to restart timer: " + std::string(uv_strerror(err)));
    }
}

void TimerHandle::InternalClose() {
    if (this->closed) {
        return;
    }

    this->closed = true;

    if (uv_handle) {
        uv_handle->data = nullptr; // Clear the data pointer before closing.
        uv_close(reinterpret_cast<uv_handle_t*>(uv_handle), static_cast<uv_close_cb>(onCloseTimer));
    }
}

inline void TimerHandle::OnUvTimer() {
    if (this->listener) {
        this->listener->OnTimer(this);
    }
}